package server.communication;

import server.data.BlokjesVerdeler;
import server.gui.Server;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Vector;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import org.apache.log4j.Logger;
import data.Gebruiker;
import data.Gameroom;
import data.Gameroom.Gametype;
import data.Score;
import data.SpelScore;
import java.awt.Color;
import java.io.ObjectOutputStream;
import server.dataaccess.GebruikerDAO;
import server.dataaccess.ScoreDAO;
import server.dataaccess.WoordenboekDAO;

public class ServerCommunication implements Runnable {

    private Logger logger = Logger.getLogger(ServerCommunication.class);
    private static ServerSocket servSock;
    private final int PORT;
    private Server frm;
    private static int aantalClients = 0;
    private boolean stateServer = false;
    private PrintWriter out;
    private BufferedReader in;
    //clienthandlers bijhouden
    private Vector<ClientHandler> clienthandlers;
    //private Hashtable<String,ClientHandler> clienthandlers;
    //adhv van een gebruikersnaam de bijhorende clienthandler ophalen
    //threadpool
    private ExecutorService pool;
    //CSAXParser
    private CSAXParserServer parser;
    private Hashtable<String, Gameroom> gamerooms = new Hashtable<String, Gameroom>();
    private Hashtable<String, Gebruiker> onlineGebruikers = new Hashtable<String, Gebruiker>();
    private Hashtable<String, BlokjesVerdeler> blokjesverdelers = new Hashtable<String, BlokjesVerdeler>();
    //private String gebruikerAanDeBeurt;
    public ServerCommunication(int poort) {
        this.PORT = poort;
        parser = new CSAXParserServer(this);

        printMessage("Starten van de ScrabbleServer");
        printMessage("Openen van de socket...");

        try {
            servSock = new ServerSocket(PORT);
            printMessage("Openen van de socket gelukt.");

            //nieuw: threadpool creeren
            pool = Executors.newCachedThreadPool();

            //clienthandlers bijhouden in vector
            clienthandlers = new Vector<ClientHandler>();

        } catch (IOException e) {
            printMessage("Openen socket mislukt!");
            logger.error(e.getMessage());
            System.exit(1);
        }
    }

    public ServerCommunication(Server frm) {
        PORT = 1234;
        this.frm = frm;
        parser = new CSAXParserServer(this);

        printMessage("Starten van de ScrabbleServer");
        printMessage("Openen van de socket...");

        //1: ServerSocket creeren
        try {
            servSock = new ServerSocket(PORT);
            printMessage("Openen van de socket gelukt.");

            //threadpool creeren
            pool = Executors.newCachedThreadPool();

            //clienthandlers bijhouden in vector
            clienthandlers = new Vector<ClientHandler>();

            stateServer = true;
        } catch (IOException e) {
            printMessage("Openen socket mislukt!");
            logger.error(e.getMessage());
            System.exit(1);
        }
    }

    public void run() {
        do {
            startServer();
        } while (stateServer);
    }

    public void spelersOphalen() {
        frm.spelersOphalen();
    }

    void getRandomWoord(int clienthandler) {
        logger.info("server doet aanvraag naar random woord");
        String w = WoordenboekDAO.getRandomWoord().getWoord();
        logger.info(w);
        for (ClientHandler c : clienthandlers) {
            if (c.getNummer() == clienthandler) {
                logger.info("zendrandomwoord versturen");
                c.zendRandomWoord(w);
            }
        }
    }

    void checkNicknameBestaatAl(String nickname, int clh) {
        boolean bestaat = GebruikerDAO.checkNicknameBestaatAl(nickname);
        for (ClientHandler c : clienthandlers) {
            if (c.getNummer() == clh) {
                c.replyCheckNicknameBestaatAl(bestaat);
            }
        }
    }

    void geefBeurtDoor(String gameNaam) {
        Gameroom room = gamerooms.get(gameNaam);

        //Eerst controleren of er nog blokjes in het zakje zitten, zo niet is het spel gedaan
        if (getBlokjesVerdeler(gameNaam) != null && getBlokjesVerdeler(gameNaam).getAantalBlokjes() == 0) {
            spelAfgelopen(room);
        } else {
            if (room.getAantalSpelers() > 0) {
                String volgendeSpeler = gamerooms.get(gameNaam).getVolgendeSpeler();
                //gebruikerAanDeBeurt = volgendeSpeler;
                room.setGebruikerAanDeBeurt(volgendeSpeler);
                for (ClientHandler clh : clienthandlers) {
                    // logger.info("de volgende speler is(volgende de gameroom): "+ gamerooms.get(gameNaam).getVolgendeSpeler());
                    // logger.info("de volgende speler is (volgende de clh): : "+ clh.getLogin());
                    if (clh.getLogin().equals(volgendeSpeler)) {
                        clh.isAanDeBeurt();
                    }
                }
                for (ClientHandler clh : clienthandlers) {
                    if (room.getSpelers().get(clh.getLogin()) != null) {
                        clh.replyToAllSpelerAanDeBeurt(volgendeSpeler);
                    }
                }
            }

        }

    //clienthandlers.get(gamerooms.get(gameNaam).getVolgendeSpeler()).isAanDeBeurt();

    }

    public void pasBeurt(String nickname, String gameName) {
        Gameroom room = gamerooms.get(gameName);

        if (room != null) {
            room.setAantalKeerGepastPerSpeler(nickname, room.getAantalKeerGepastPerSpeler().get(nickname) + 1);

            //Controleren of alle spelers in het spel hetzelfde aantal keer na elkaar
            //gepast hebben, zo ja => spel gedaan!
            boolean maxAantalKeerGepast = true;
            for (String nick : room.getSpelers().keySet()) {
                if (room.getAantalKeerGepastPerSpeler().get(nick).intValue() == room.getMaxAantalKeerGepast()) {
                    maxAantalKeerGepast &= true;
                } else {
                    maxAantalKeerGepast &= false;
                }
            }

            if (room.getSpelers().size() > 0 && maxAantalKeerGepast) {
                logger.info("Max aantal keer gepast => spel zal stoppen...");
                spelAfgelopen(room);
            } else {
                //beurt doorgeven
                geefBeurtDoor(gameName);
            }
        }
    }

    public void beurtVerlopen(String nickname, String gameNaam) {
        Gameroom room = gamerooms.get(gameNaam);

        if (room != null) {
            room.setAantalKeerBeurtVerlopenPerSpeler(nickname, room.getAantalKeerBeurtVerlopenPerSpeler().get(nickname).intValue() + 1);

            //Checken of de speler max aantal keer beurt heeft laten verlopen
            if (room.getAantalKeerBeurtVerlopenPerSpeler().get(nickname).intValue() == room.getMaxAantalKeerBeurtVerlopen()) {
                logger.info("Max aantal keer beurt verlopen voor speler: " + nickname);

                Gebruiker banned = onlineGebruikers.get(nickname);
                if (banned != null) {
                    for (ClientHandler clh : clienthandlers) {
                        if (room.getSpelers().get(clh.getLogin()) != null) {
                            clh.replyMaxBeurtVerlopen(nickname);
                        }
                    }
                    room.removeSpelers(banned);
                    //Dit lijntje moet er staan of beurt wordt verkeerd doorgegeven
                    room.setBeurtIndex(room.getBeurtIndex() - 1);

                    for (ClientHandler clh : clienthandlers) {
                        if (room.getSpelers().get(clh.getLogin()) != null) {
                            clh.replyUpdateScoreLijst(room);
                        }
                    }
                }
            }
        }
    }

    public void spelAfgelopen(Gameroom room) {
        logger.info("Spel afgelopen!");
        room.setSpelAfgelopen(true);

        //Scores worden enkel opgeslagen als je met meer dan 1 speler speelt
        /*if (room.getAantalSpelers() > 1 && winnaars.size() >= 1) {
        for (String nick : winnaars) {
        Gebruiker winnaar = GebruikerDAO.getGebruikerByLogin(nick);
        Score score = ScoreDAO.getScoreById(winnaar.getScoreId());
        if (room.getType().toString().equals("SCRABBLE")) {
        score.setScrabbleGewonnen(score.getScrabbleGewonnen() + 1);
        score.setScrabbleScore(score.getScrabbleScore() + room.getScores().get(nick).intValue());
        }
        ScoreDAO.updateScore(score);
        }
        //Nu overlopen wie geen winnaar is, en hun score "verloren" aanpassen
        for (String verliezer : room.getSpelers().keySet()) {
        if (!winnaars.contains(verliezer)) {
        Gebruiker loser = GebruikerDAO.getGebruikerByLogin(verliezer);
        Score score = ScoreDAO.getScoreById(loser.getScoreId());
        if (room.getType().toString().equals("SCRABBLE")) {
        score.setScrabbleVerloren(score.getScrabbleVerloren() + 1);
        score.setScrabbleScore(score.getScrabbleScore() + room.getScores().get(verliezer).intValue());
        }
        ScoreDAO.updateScore(score);
        }
        }
        }*/

        for (ClientHandler clh : clienthandlers) {
            if (room.getSpelers().get(clh.getLogin()) != null) {
                clh.replySpelAfgelopen();
            }
        }
    }

    public void scoreOpslaan(ArrayList<String> overblijvendeLetters, String nickname, String roomName) {
        Gameroom room = gamerooms.get(roomName);

        room.setAantalSpelersGeantwoord(room.getAantalSpelersGeantwoord() + 1);

        int score = room.getScores().get(nickname);
        for (String letter : overblijvendeLetters) {
            score -= getBlokjesVerdeler(roomName).getLetterWaarde(letter);
        }

        if (score < 0) {
            score = 0;
        }

        room.addScore(nickname, score);

        //Enkel als alle spelers hun overblijvende letters hebben teruggestuurd,
        //mogen de scores opgeslagen worden in de database en de winnaar bepaald worden
        if (room.getAantalSpelersGeantwoord() == room.getAantalSpelers()) {
            //Winnaar(s) bepalen en scores opslaan in database
            ArrayList<String> winnaars = room.bepaalWinnaars();

            //Enkel de scores opslaan als je met meer dan 1 speler speelt
            if (room.getAantalSpelers() > 1) {
                for (String nick : room.getSpelers().keySet()) {
                    //Score updaten
                    Gebruiker speler = GebruikerDAO.getGebruikerByLogin(nick);
                    Score s = ScoreDAO.getScoreById(speler.getScoreId());
                    if (room.getType().toString().equals("SCRABBLE")) {
                        if (winnaars.contains(nick)) {
                            s.setScrabbleGewonnen(s.getScrabbleGewonnen() + 1);
                        } else {
                            s.setScrabbleVerloren(s.getScrabbleVerloren() + 1);
                        }
                        if (s.getScrabbleScore() < room.getScores().get(nick)) {
                            s.setScrabbleScore(room.getScores().get(nick));
                        }
                    }
                    ScoreDAO.updateScore(s);
                }
            }

            for (ClientHandler clh : clienthandlers) {
                if (room.getSpelers().get(clh.getLogin()) != null) {
                    clh.replyUpdateScoreLijst(room);
                    clh.replyToonWinnaars(winnaars);
                }
            }

        }
    }

    public void replyStuurBoggleBord(String nickname, String[][] bogglebord) {
        for (ClientHandler clh : clienthandlers) {
                if (clh.getLogin().equals(nickname)) {
                    clh.replyStuurBoggleBord(bogglebord);
                }
            }
    }

    public void startAvatarSocket(int clh, String filename) {
        try {
            int poort = 9876;
            Socket link = null;
            ServerSocket AvatarSock = new ServerSocket(poort);
            for (ClientHandler c : clienthandlers) {
                if (c.getNummer() == clh) {
                    c.replyZendAvatarAanvraag(poort);
                }

            }
            link = AvatarSock.accept();
            InputStream ins = link.getInputStream();
            ObjectInputStream objin = new ObjectInputStream(ins);

            ImageIcon icon = (ImageIcon) objin.readObject();
            saveImage(icon.getImage(), filename);

            logger.info("na icon ontvangen");
            objin.close();
            ins.close();
            AvatarSock.close();
            link.close();
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(ServerCommunication.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            logger.info("Fout bij het opstarten van avatar socket");
        }

    }

    public static void saveImage(final Image image,
            final String filename)
            throws IOException {
        final int w = image.getHeight(null);
        final int h = image.getHeight(null);
        final BufferedImage bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        final Graphics2D g2 = bi.createGraphics();
        g2.drawImage(image, 0, 0, null);
        g2.dispose();
        if (new File("../ScrabbleProject/Avatars").exists()) {
            final File file = new File("../ScrabbleProject/Avatars/" + filename);
            ImageIO.write(bi, "jpg", file);
        } else {
            (new File("../ScrabbleProject/Avatars")).mkdir();
            final File file = new File("../ScrabbleProject/Avatars/" + filename);
            ImageIO.write(bi, "jpg", file);
        }

    }

    public void startGeefAvatarSocket(String nickname,int clh) {
        try {
            int poort = 9654;
            Socket link = null;
            ServerSocket AvatarSock = new ServerSocket(poort);
            for (ClientHandler c : clienthandlers) {
                if (c.getNummer() == clh) {
                    c.replyGetAvatarAanvraag(poort);
                }

            }
            Gebruiker g = onlineGebruikers.get(nickname);
            link = AvatarSock.accept();
            //blabla
            ObjectOutputStream out = new ObjectOutputStream(link.getOutputStream());
            logger.info((new File("../ScrabbleProject"+g.getAvatar())).exists());
            BufferedImage img = ImageIO.read(new File("../ScrabbleProject"+g.getAvatar()));
            Color c = new Color(img.getRGB(0, 0));
            ImageIcon imgi = new ImageIcon(img);
            out.writeObject(imgi);
            out.flush();
            out.close();
            AvatarSock.close();
            link.close();

        } catch (IOException ex) {
            logger.info("Fout bij het opstarten van avatar socket");
        }
    }

    public Score getScore(int i) {
        return ScoreDAO.getScoreById(i);
    }

    void updateScore(Score score) {
        ScoreDAO.updateScore(score);
    }

    private void startServer() {
        Socket link = null;
        try {
            printMessage("Server staat aan");
            //wachten op client
            printMessage("Server: wachttoestand");
            link = servSock.accept();
            printMessage("Server: Nieuwe connectie met client geaccepteerd.");

            //input & outputkanaal ingesteld
            in =
                    new BufferedReader(new InputStreamReader(link.getInputStream()));
            out =
                    new PrintWriter(link.getOutputStream(), true);

            //Clienthandler aanmaken en bijhouden in server
            ClientHandler chl = new ClientHandler(link, aantalClients, this);
            clienthandlers.add(chl);
            //clienthandlers.put("", chl);

            //ClienHandler opstarten en als thread starten
            Thread clhThread = new Thread(chl);
            pool.execute(clhThread);

            printMessage("Server: Connection with client " + aantalClients + " established.");

            aantalClients++;

        } catch (java.io.IOException ioe) {
            printMessage("Connectie met client niet geslaagd.");
            logger.error(ioe.getMessage());
        }

    }

    public static int aantalClients() {
        return aantalClients;
    }

    public void stopServer() {
        try {
            stateServer = false;
            if (pool != null) {
                pool.shutdown();
            }
//clienthandlers sluiten
            for (ClientHandler clh : clienthandlers) {
                clh.closeConnectionClient();
            }
//serverSocket sluiten
            if (!servSock.isClosed()) {
                servSock.close();
            }

            printMessage("Connectie sluiten: geslaagd");
        } catch (IOException ex) {
            logger.error("Fout bij het afsluiten van de server!");
            logger.error(ex.getClass() + " - " + ex.getMessage());
        }

    }

    public void printMessage(String message) {
        logger.info(message);
        frm.printMessage(message);
    }

    public void printSpelers(String message) {
        //de online spelers weergeven
        frm.printSpelers(message);
    }

    public void cleartxtSpelers() {
        frm.cleartxtSpelers();
    }

    public void zendChatBerichtNaarIedereen(String afzender, String bericht) {
        for (ClientHandler clh : clienthandlers) {
            clh.zendBericht(afzender, bericht);
        }

    }

    //doorgeven af een speler al dan niet al ingelogd is
    public void spelerAlOnline(String login, int clhNr) {
        boolean b = false;
        for (ClientHandler clh : clienthandlers) {
            if (login.equals(clh.getLogin())) {
                b = true;
            }

        }
        for (ClientHandler c : clienthandlers) {
            if (c.getNummer() == clhNr) {
                c.spelerIsAlOnline(b);
            }

        }
    }

    public void voegGebruikerToe(Gebruiker g) {
        GebruikerDAO.voegGebruikerToe(g);
    }

    public void updateSpeler(Gebruiker g) {

        GebruikerDAO.updateGebruiker(g);
    }

    public void loginGebruiker(int ch, String nickname, String password) {
        Gebruiker g = GebruikerDAO.checkLoginGegevens(nickname, password);

        for (ClientHandler c : clienthandlers) {
            if (c.getNummer() == ch) {
                c.bestaatSpeler(g);
            }

        }
    }

    void GetSpelerByNickname(int clienthandler, String nickname) {
        logger.info("opzoekaanvraag voor db van nickname " + nickname);
        Gebruiker g = GebruikerDAO.getGebruikerByLogin(nickname);
        Score s = ScoreDAO.getScoreById(g.getScoreId());
        for (ClientHandler c : clienthandlers) {
            if (c.getNummer() == clienthandler) {
                c.stuurGegevensSpeler(g, s);
            }

        }
    }

    public void onlineSpelersOphalen() {
        ArrayList<Gebruiker> spelers = GebruikerDAO.getOnlineNonGamingGebruikers();

        //De online gebruikers naar iedereen doorsturen
        frm.spelersOphalen();
        for (ClientHandler clh : clienthandlers) {
            clh.onlineSpelers(spelers);
        }

    }

    //login aan de andere clients doorgeven
    public void zendLoginNaarAndereClient(int ch, String login) {
        for (ClientHandler clh : clienthandlers) {
            clh.zendLogin(login);
            if (clh.getNummer() == ch) {
                clh.setLogin(login);
            }

        }

        updateOnlineGebruikersLijst();
    }

    public void updateOnlineGebruikersLijst() {
        // De online gebruikerslijst aan serverkant updaten
        ArrayList<Gebruiker> gebruikersOnline;
        gebruikersOnline =
                GebruikerDAO.getOnlineGebruikers();
        cleartxtSpelers();
        for (Gebruiker g : gebruikersOnline) {
            printSpelers(g.getNickname());
        }

//De online gebruikers langs serverkant bijhouden
        onlineGebruikers.clear();
        for (Gebruiker g : gebruikersOnline) {
            onlineGebruikers.put(g.getNickname(), g);
        }

        updateGamerooms();
    }

    private void updateGamerooms() {
        //Nagaan of alle spelers die in een gameroom zitten nog online zijn
        //zoniet gooien we ze eruit:

        //"Speciale" manier om de Hashtable te overlopen: via Iterator ipv via Enumeration 
        //of keySet():
        //ConcurrentModificationException treedt op omdat ik elementen uit de hashtable
        //wil verwijderen met gamerooms.remove() die ik terzelfdertijd overloop in een for-lus.
        //Via deze Iterator is het probleem opgelost, de fout treedt niet meer op
        for (Iterator i = gamerooms.entrySet().iterator(); i.hasNext();) {
            Map.Entry entry = (Map.Entry) i.next();
            Gameroom room = (Gameroom) entry.getValue();
            for (String nickname : room.getSpelers().keySet()) {
                Gebruiker g = onlineGebruikers.get(nickname);
                if (g == null) {
                    room.removeSpelers(room.getSpelers().get(nickname));
                }

            }

            //Als alle spelers offline gingen en de gameroom is dus leeg,
            //verwijder ze dan uit de lijst van gamerooms
            if (room.getAantalSpelers() == 0) {
                i.remove();
            }

        }

        //Doorgeven aan alle andere clients
        for (ClientHandler clh : clienthandlers) {
            clh.replyGetGamerooms(gamerooms);
        }

    }

    //laten weten dat een speler offline gegaan is
    public void spelerOffline(String login) {
        //Laten weten aan alle andere clients dat de speler offline is
        printMessage(login + " is offline");
        ClientHandler clhToRemove = null;
        for (ClientHandler clh : clienthandlers) {
            clh.spelerOffline(login);
            if (login.equals(clh.getLogin())) {
                //andere clienthandler aan gelijkstellen,omdat het niet mogelijk is een collectie aan te passen
                // terwijl er een iteratie over loopt.
                clhToRemove = clh;
            }

        }
        if (clhToRemove != null) {
            clienthandlers.remove(clhToRemove);
        }

// De online gebruikerslijst aan serverkant updaten
        updateOnlineGebruikersLijst();
    }

    public void zendPriveBericht(String afzender, String bericht, String ontvanger) {
        logger.debug("Server: zend bericht naar client: " + ontvanger);
        for (ClientHandler clh : clienthandlers) {
            if (clh.getLogin().equals(ontvanger)) {
                clh.zendPriveBericht(afzender, bericht);
            }

        }
    }

    public void getGamerooms(int clhNr) {
        for (ClientHandler clh : clienthandlers) {
            if (clh.getNummer() == clhNr) {
                clh.replyGetGamerooms(gamerooms);
            }

        }
    }

    public void joinGameroom(String nickname, String gameNaam) {
        //Speler in de database op gaming=true plaatsen
        Gebruiker g = onlineGebruikers.get(nickname);
        if (g != null) {
            g.setGaming(true);
            GebruikerDAO.updateGebruiker(g);
            frm.printMessage(nickname + " heeft gameroom " + gameNaam + " gejoined.");
        }

//Speler toevoegen aan de gameroom
        Gameroom room = gamerooms.get(gameNaam);
        if (room != null) {
            room.addSpelers(onlineGebruikers.get(nickname));
        }

//Clienthandlers overlopen, en enkel naar de spelers die in de gameroom zitten
//doorsturen dat iemand het spel heeft gejoined
        for (ClientHandler clh : clienthandlers) {
            if (room.getSpelers().get(clh.getLogin()) != null) {
                clh.replySpelerJoined(nickname);
                clh.replyUpdateScoreLijst(room);
            }

        }

        //Doorgeven aan alle andere clients
        for (ClientHandler clh : clienthandlers) {
            clh.replyGetGamerooms(gamerooms);
            clh.replyToAllSpelerInGame(nickname);
        }

//doorgeven van letterwaarde
        if (room.getType().equals(Gametype.SCRABBLE)) {
            this.AanvraagLetterWaarde(nickname, gameNaam);
        }
        
        if(room.getType().equals(Gametype.BOGGLE)){
            logger.info("gametype is boggle");
            for (ClientHandler clh : clienthandlers) {
                if (gamerooms.get(gameNaam).getNicknameOprichter().equals(clh.getLogin())) {
                    clh.StuurBord(nickname);
                }

            }
        }

        //De online non-gaming spelerslijst updaten

        onlineSpelersOphalen();
    }

    public void leaveGame(String nickname, String gameNaam) {
        Gebruiker g = onlineGebruikers.get(nickname);
        Gameroom room = gamerooms.get(gameNaam);
        if (g != null) {
            if (room != null) {
                room.removeSpelers(g);
                if (g.getNickname().equals(room.getNicknameOprichter())) {
                    if (room.getAantalSpelers() > 0) {
                        room.setNicknameOprichter(room.getSpelers().keys().nextElement());
                    } else if (room.getAantalSpelers() == 0 && room.getType().equals(Gametype.SCRABBLE)) {
                        blokjesverdelers.remove(gameNaam);
                    }

                }
                frm.printMessage(nickname + " heeft gameroom " + gameNaam + " verlaten.");
            }

            g.setGaming(false);
            GebruikerDAO.updateGebruiker(g);

            //Aan de overgebleven spelers in het spel melden dat iemand het spel verliet
            for (ClientHandler clh : clienthandlers) {
                if (room != null && room.getSpelers().get(clh.getLogin()) != null) {
                    clh.replyLeaveGame(nickname);
                    clh.replyUpdateScoreLijst(room);
                }

            }
        }

        if (room != null && nickname.equals(room.getGebruikerAanDeBeurt()) && room.isSpelGestart() && !room.isSpelAfgelopen()) {
            //Beurt volgende speler op true
            geefBeurtDoor(gameNaam);
        }

        onlineSpelersOphalen();
        updateGamerooms();
    }

    public void startSpel(String gameNaam) {
        Gameroom room = gamerooms.get(gameNaam);
        if (room != null) {
            room.setSpelGestart(true);
            //Aan alle spelers in het spel melden dat het spel gestart is
            //maw: iedereen krijgt blokjes verdeeld
            for (ClientHandler clh : clienthandlers) {
                if (room.getSpelers().get(clh.getLogin()) != null) {
                    clh.spelGestart(gameNaam);
                }

            }
        }

        updateGamerooms();
    }

    public BlokjesVerdeler getBlokjesVerdeler(
            String gameName) {
        if (blokjesverdelers.containsKey(gameName)) {
            return blokjesverdelers.get(gameName);
        } else {
            return null;
        }

    }

    public void gameroomAanmaken(Gameroom gameroom, int clhNr) {
        boolean aangemaakt;
        if (gamerooms.get(gameroom.getGamenaam()) == null) {
            aangemaakt = true;
            gamerooms.put(gameroom.getGamenaam(), gameroom);
            if (gameroom.getType().equals(Gametype.SCRABBLE)) {
                blokjesverdelers.put(gameroom.getGamenaam(), new BlokjesVerdeler());
            }

        } else {
            aangemaakt = false;
        }

        for (ClientHandler clh : clienthandlers) {
            if (clh.getNummer() == clhNr) {
                if (aangemaakt) {
                    //Speler in de database op gaming=true plaatsen
                    Gebruiker g = onlineGebruikers.get(gamerooms.get(gameroom.getGamenaam()).getNicknameOprichter());
                    if (g != null) {
                        g.setGaming(true);
                        GebruikerDAO.updateGebruiker(g);
                    }

                    //gebruikerAanDeBeurt = g.getNickname();
                    gameroom.setGebruikerAanDeBeurt(g.getNickname());

                    //De online non-gaming spelerslijst updaten
                    onlineSpelersOphalen();
                }

                clh.createGameroom(aangemaakt, gameroom.getType());
            }

        }
        if (aangemaakt) {
            frm.printMessage(gameroom.getNicknameOprichter() + " heeft een " + gameroom.getType().toString() + " gameroom " + gameroom.getGamenaam() + " aangemaakt.");
            for (ClientHandler clh : clienthandlers) {
                clh.gameroomToevoegen(gameroom);
                clh.replyToAllSpelerInGame(gameroom.getNicknameOprichter());
                if (gameroom.getType().equals(Gametype.SCRABBLE)) {
                    clh.AanvraagLetterWaarde(gameroom.getGamenaam());
                }
            }

        }

    }

    public void zendChatBerichtInGame(String nickname, String gameNaam, String bericht) {
        Gameroom room = gamerooms.get(gameNaam);

        //Clienthandlers overlopen, en enkel naar de spelers die in de gameroom zitten
        //het bericht doorsturen
        for (ClientHandler clh : clienthandlers) {
            if (room.getSpelers().get(clh.getLogin()) != null && !clh.getLogin().equals(nickname)) {
                clh.replyChatBerichtInGame(nickname, bericht);
            }

        }
    }

    public CSAXParserServer getParser() {
        return parser;
    }

    /*
     * @return geeft een lijst van oorden terug die NIET in de woordenboek voorkomen
     */
    public void woordvalidatie(String nickname, String roomName, ArrayList<String> arlWoorden, int score) {

        ArrayList<String> fouteWoorden = new ArrayList<String>();
        logger.info("woordvalidatie aantal woorden gevormd: " + arlWoorden.size());
        for (int i = 0; i <
                arlWoorden.size(); i++) {
            logger.info("Gevormde woorden: " + arlWoorden.get(i));
            boolean woordGevonden = WoordenboekDAO.getWoord(arlWoorden.get(i));
            if (!woordGevonden) {
                fouteWoorden.add(arlWoorden.get(i));
            }

        }

        for (int i = 0; i <
                fouteWoorden.size(); i++) {
            if (fouteWoorden.get(i).length() == 1) {
                fouteWoorden.remove(i);
            }

        }

        Gameroom room = gamerooms.get(roomName);
        if (fouteWoorden.size() == 0) {
            //Score instellen van de gebruiker en doorsturen
            if (room != null) {
                room.addScore(nickname, room.getScores().get(nickname).intValue() + score);
            }

            for (ClientHandler clh : clienthandlers) {
                if (room.getSpelers().get(clh.getLogin()) != null) {
                    clh.replyUpdateScoreLijst(room);
                }

            }
        }

        for (ClientHandler clh : clienthandlers) {
            if (room.getSpelers().get(clh.getLogin()) != null) {
                logger.info("de woorden worden doorgestuurd naar clienhandler:");
                clh.zendNietGeldigeWoorden(fouteWoorden);
            }

        }
    }
    
    public void woordNakijken(String nickname, String roomName, ArrayList<String> arlWoorden) {
        int score=0;
        ArrayList<String> goedeWoorden = new ArrayList<String>();
        logger.info("woordvalidatie aantal woorden gevormd: " + arlWoorden.size());
        for (int i = 0; i < arlWoorden.size(); i++) {
            logger.info("Gevormde woorden: " + arlWoorden.get(i));
            boolean woordGevonden = WoordenboekDAO.getWoord(arlWoorden.get(i));
            if (woordGevonden) {
                goedeWoorden.add(arlWoorden.get(i));
            }
            logger.info(arlWoorden.get(i).length());
            if (arlWoorden.get(i).length() == 3 || arlWoorden.get(i).length() == 4) {
                score += 1;
            } else if (arlWoorden.get(i).length() == 5) {
                score += 2;
            } else if (arlWoorden.get(i).length() == 6) {
                score += 3;
            } else if (arlWoorden.get(i).length() == 7) {
                score += 5;
            } else if (arlWoorden.get(i).length() >= 8) {
                score += 11;
            }
            

        }
        logger.info("score"+score);
        logger.info("na woordenboek, size goedeWoorden: " + goedeWoorden.size());
        Gameroom room = gamerooms.get(roomName);
        if (score != 0) {
            //Score instellen van de gebruiker en doorsturen
            if (room != null) {
                room.addScore(nickname, room.getScores().get(nickname).intValue() + score);
            }

            for (ClientHandler clh : clienthandlers) {
                if (room.getSpelers().get(clh.getLogin()) != null) {
                    clh.replyUpdateScoreLijst(room);
                }

            }
        }

        for (ClientHandler clh : clienthandlers) {
            if (clh.getLogin().equals(nickname)) {
                logger.info("de woorden worden doorgestuurd naar clienhandler:");
                clh.zendGoedeWoorden(goedeWoorden);
            }

        }
    }

    //een speler heeft een blokje op hets pelbord verplaatst
    //dit moet voor de medespelers zichtbaar zijn
    public void verplaatsBlokje(Point positie, Point oudePositie, String letter, boolean blanco, int clhNr, String gameNaam) {
        Gameroom room = gamerooms.get(gameNaam);
        for (ClientHandler clh : clienthandlers) {
            if (room.getSpelers().get(clh.getLogin()) != null && clh.getNummer() != clhNr) {
                clh.verplaatsBlokje(positie, oudePositie, letter, blanco);
            }

        }
    }

    public void geefAantalBlokjes(int aantal, String ontvanger, String gameNaam) {
        //aantal keer gepast van alle spelers terug op 0 zetten als een speler blokjes ruilt
        //of als hij een juist woord gelegd heeft (en dus terug nieuwe blokjes krijgt)
        Gameroom room = gamerooms.get(gameNaam);
        for (String speler : room.getSpelers().keySet()) {
            room.setAantalKeerGepastPerSpeler(speler, 0);
        }

        //Aantal keer achtereenvolgns beurt verlopen van speler terug op 0 zetten
        room.setAantalKeerBeurtVerlopenPerSpeler(ontvanger, 0);

        for (ClientHandler clh : clienthandlers) {
            if (clh.getLogin().equals(ontvanger)) {
                clh.zendLetters(this.getBlokjesVerdeler(gameNaam).geefblokjes(aantal));
            }

        }

        vraagAantalBlokjesResterend(gameNaam);
    }

    private void vraagAantalBlokjesResterend(String gameNaam) {
        Gameroom room = gamerooms.get(gameNaam);

        for (ClientHandler clh : clienthandlers) {
            if (room.getSpelers().get(clh.getLogin()) != null) {
                clh.zendAantalBlokjesResterendInZakje(this.getBlokjesVerdeler(room.getGamenaam()).getAantalBlokjes());
            }

        }
    }

    void geefLettersTerug(ArrayList<String> letterLijst, String gameNaam) {
        logger.info("In gameroom " + gameNaam + " worden letters teruggestoken in het zakje.");
        this.getBlokjesVerdeler(gameNaam).steekBlokjesTerugInZakje(letterLijst);

        vraagAantalBlokjesResterend(gameNaam);
    }

    public void AanvraagLetterWaarde(String ontvanger, String gamenaam) {
        for (ClientHandler clh : clienthandlers) {
            if (clh.getLogin().equals(ontvanger)) {
                clh.AanvraagLetterWaarde(gamenaam);
            }
        }
    }

    public void bepaalTopscore(Gametype gametype, String nickname) {
        SpelScore[] scores = null;
        switch (gametype) {
            case GALGJE:
                scores = ScoreDAO.getTopscoreGalgje();
                break;
            case BOGGLE:
                scores = ScoreDAO.getTopscoreBoggle();
                break;
            case SCRABBLE:
                scores = ScoreDAO.getTopscoreScrabble();
                break;
        }
        for (ClientHandler clh : clienthandlers) {
            if (clh.getLogin().equals(nickname)) {
                clh.topscoreBepaald(scores);
            }
        }
    }
}
